﻿
using Xacml.Core;
using Xacml.Core.Interfaces;
using Xacml.Core.Runtime;
using Xacml.Core.Runtime.DataTypes;
using System;
using System.Collections;
using System.Globalization;
using System.Xml;

namespace Xacml.Core.Policy
{
  public abstract class StringValueBase : XacmlElement, IFunctionParameter
  {
    public abstract string Value { get; set; }

    public abstract string DataTypeValue { get; set; }

    public bool IsBag
    {
      get
      {
        return false;
      }
    }

    public int BagSize
    {
      get
      {
        return 0;
      }
    }

    public ArrayList Elements
    {
      get
      {
        return (ArrayList) null;
      }
    }

    protected StringValueBase(XacmlSchema schema, XacmlVersion schemaVersion)
      : base(schema, schemaVersion)
    {
    }

    public IDataType GetType(EvaluationContext context)
    {
      return context.Engine.GetDataType(this.DataTypeValue);
    }

    public object GetTypedValue(IDataType dataType, int parNo)
    {
      if (this.IsBag)
        return (object) this;
      if (this.DataTypeValue != dataType.DataTypeName)
        throw new EvaluationException("invalid data type");
      switch (this.DataTypeValue)
      {
        case "urn:oasis:names:tc:xacml:1.0:data-type:x500Name":
          return (object) this.GetX500Name(parNo);
        case "urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name":
          return (object) this.GetRfc822Name(parNo);
        case "http://www.w3.org/2001/XMLSchema#string":
          return (object) this.GetString(parNo);
        case "http://www.w3.org/2001/XMLSchema#boolean":
		  return (object)(this.GetBoolean(parNo) ? true : false);
        case "http://www.w3.org/2001/XMLSchema#integer":
          return (object) this.GetInteger(parNo);
        case "http://www.w3.org/2001/XMLSchema#double":
          return (object) this.GetDouble(parNo);
        case "http://www.w3.org/2001/XMLSchema#time":
          return (object) this.GetTime(parNo);
        case "http://www.w3.org/2001/XMLSchema#date":
          return (object) this.GetDate(parNo);
        case "http://www.w3.org/2001/XMLSchema#dateTime":
          return (object) this.GetDateTime(parNo);
        case "http://www.w3.org/2001/XMLSchema#anyURI":
          return (object) this.GetAnyUri(parNo);
        case "http://www.w3.org/2001/XMLSchema#hexBinary":
          return (object) this.GetHexBinary(parNo);
        case "http://www.w3.org/2001/XMLSchema#base64Binary":
          return (object) this.GetBase64Binary(parNo);
        case "http://www.w3.org/TR/2002/WD-xquery-operators-20020816#dayTimeDuration":
          return (object) this.GetDayTimeDuration(parNo);
        case "http://www.w3.org/TR/2002/WD-xquery-operators-20020816#yearMonthDuration":
          return (object) this.GetYearMonthDuration(parNo);
        default:
          throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
          {
            (object) parNo,
            (object) this.DataTypeValue
          }]);
      }
    }

    public IFunction GetFunction(int parNo)
    {
      throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
      {
        (object) parNo,
        (object) this.DataTypeValue
      }]);
    }

    private bool GetBoolean(int parNo)
    {
      if (this.DataTypeValue != null && this.DataTypeValue != "http://www.w3.org/2001/XMLSchema#boolean")
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }]);
      return XmlConvert.ToBoolean(this.Value);
    }

    private string GetString(int parNo)
    {
      if (this.DataTypeValue != null && this.DataTypeValue != "http://www.w3.org/2001/XMLSchema#string")
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }]);
      return this.Value;
    }

    private HexBinary GetHexBinary(int parNo)
    {
      if (this.DataTypeValue != null && this.DataTypeValue != "http://www.w3.org/2001/XMLSchema#hexBinary")
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }]);
      byte[] numArray = new byte[this.Value.Length / 2];
      for (int index = 0; index < numArray.Length; ++index)
        numArray[index] = byte.Parse(this.Value.Substring(index * 2, 2), NumberStyles.HexNumber, (IFormatProvider) CultureInfo.InvariantCulture);
      return new HexBinary(numArray);
    }

    private Base64Binary GetBase64Binary(int parNo)
    {
      if (this.DataTypeValue != null && this.DataTypeValue != "http://www.w3.org/2001/XMLSchema#base64Binary")
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }]);
      return new Base64Binary(Convert.FromBase64String(this.Value));
    }

    private Uri GetAnyUri(int parNo)
    {
      if (this.DataTypeValue != null)
      {
        if (this.DataTypeValue != "http://www.w3.org/2001/XMLSchema#anyURI")
          throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
          {
            (object) parNo,
            (object) this.DataTypeValue
          }]);
      }
      try
      {
        return new Uri(this.Value);
      }
      catch (Exception ex)
      {
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }], ex);
      }
    }

    private int GetInteger(int parNo)
    {
      if (this.DataTypeValue != null)
      {
        if (this.DataTypeValue != "http://www.w3.org/2001/XMLSchema#integer")
          throw new Exception(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
          {
            (object) parNo,
            (object) this.DataTypeValue
          }]);
      }
      try
      {
        return XmlConvert.ToInt32(this.Value);
      }
      catch (Exception ex)
      {
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }], ex);
      }
    }

    private double GetDouble(int parNo)
    {
      if (this.DataTypeValue != null)
      {
        if (this.DataTypeValue != "http://www.w3.org/2001/XMLSchema#double")
          throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
          {
            (object) parNo,
            (object) this.DataTypeValue
          }]);
      }
      try
      {
        return XmlConvert.ToDouble(this.Value);
      }
      catch (Exception ex)
      {
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }], ex);
      }
    }

    private X500Name GetX500Name(int parNo)
    {
      if (this.DataTypeValue != null)
      {
        if (this.DataTypeValue != "urn:oasis:names:tc:xacml:1.0:data-type:x500Name")
          throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
          {
            (object) parNo,
            (object) this.DataTypeValue
          }]);
      }
      try
      {
        return new X500Name(this.Value);
      }
      catch (Exception ex)
      {
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }], ex);
      }
    }

    private Rfc822Name GetRfc822Name(int parNo)
    {
      if (this.DataTypeValue != null)
      {
        if (this.DataTypeValue != "urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name")
          throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
          {
            (object) parNo,
            (object) this.DataTypeValue
          }]);
      }
      try
      {
        return new Rfc822Name(this.Value);
      }
      catch (Exception ex)
      {
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }], ex);
      }
    }

    private System.DateTime GetTime(int parNo)
    {
      if (this.DataTypeValue != null && this.DataTypeValue != "http://www.w3.org/2001/XMLSchema#time")
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }]);
      return XmlConvert.ToDateTime(this.Value, "HH:mm:sszzzzzz");
    }

    private System.DateTime GetDate(int parNo)
    {
      if (this.DataTypeValue != null && this.DataTypeValue != "http://www.w3.org/2001/XMLSchema#date")
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }]);
      return XmlConvert.ToDateTime(this.Value, "yyyy-MM-dd");
    }

    private System.DateTime GetDateTime(int parNo)
    {
      if (this.DataTypeValue != null && this.DataTypeValue != "http://www.w3.org/2001/XMLSchema#dateTime")
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }]);
      return XmlConvert.ToDateTime(this.Value, "yyyy-MM-ddTHH:mm:sszzzzzz");
    }

    private YearMonthDuration GetYearMonthDuration(int parNo)
    {
      if (this.DataTypeValue != null && this.DataTypeValue != "http://www.w3.org/TR/2002/WD-xquery-operators-20020816#yearMonthDuration")
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }]);
      return new YearMonthDuration(this.Value);
    }

    private DayTimeDuration GetDayTimeDuration(int parNo)
    {
      if (this.DataTypeValue != null && this.DataTypeValue != "http://www.w3.org/TR/2002/WD-xquery-operators-20020816#dayTimeDuration")
        throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_datatype_in_stringvalue, new object[2]
        {
          (object) parNo,
          (object) this.DataTypeValue
        }]);
      return new DayTimeDuration(this.Value);
    }
  }
}
